package com.alibaba.dubbo.common.inet.ipv4;

import java.net.InetAddress;
import java.net.InetSocketAddress;

import com.alibaba.dubbo.common.inet.IPMatcherException;
import com.alibaba.dubbo.common.inet.InetAddressSupport;
import com.alibaba.dubbo.common.inet.InetAddressMatcher;


/**
 * ipv4地址相等，允许某一段包括*通配符 192.168.2.3 192.168.*.* 192.168 等价于 192.168.*.*
 * 
 * @author kingbo.ruan 2014.09.24
 *
 */
public class WildcardEqMatcher implements InetAddressMatcher {
	int[] parts;
	long address = -1;
	public WildcardEqMatcher(String address) {
		this.parts = new int[4];
		this.parts[0] = this.parts[1] = this.parts[2] = this.parts[3] = -1;
		// 不检查有效性
		String[] parts = address.trim().split("\\.");
		if (parts.length > 4) {
			throw new IPMatcherException("Malformed IP specification " + address);
		}

		try {
			for (int i = 0; i < parts.length; i++) {
				//*表示通配，或者两个. 之间无任何字符
				String part = parts[i];
				if(!part.equals("*") && part.length() > 0){
					int p = Integer.parseInt(parts[i]);
					if (p < 0 || p > 255) {
						throw new IPMatcherException("Malformed IP specification " + address);
					}
					this.parts[i] = p;
				}
			}
		} catch (NumberFormatException nfe) {
			throw new IPMatcherException("Malformed IP specification "
					+ address, nfe);
		}
		
		boolean wildcard = false;
		for(int i = 0;i<this.parts.length;i++){
			if(this.parts[i] == -1){
				wildcard = true;
				break;
			}
		}
		if(!wildcard){
			this.address = InetAddressSupport.ipToLong(this.parts);
		}
	}

	@Override
	public boolean match(InetAddress address) {
		byte [] bytes = address.getAddress();
		if(this.address != -1){
			return this.address == InetAddressSupport.ipToLong(address);
		}else{
			if(bytes.length != parts.length ) return false;
			for(int i = 0;i<parts.length;i++){
				int part = parts[i];
				//-1表示通配
				if(part == -1) continue;
				int p = bytes[i];
				if(p < 0) p += 256;
				if(part != p) return false;
			}
			return true;
		}
	}
	
	@Override
	public InetAddress select(InetAddress[] addresses) {
		for(InetAddress address : addresses){
			if(this.match(address)) return address;
		}
		return null;
	}
}
